# Build a "circle" icon handle at the object origin.
#
new = handleclass(pos, o) # the "circle" icon would be qhandles.mapicons[10], but it looks better with the entity icon itself
#
# Set the hint as the entity classname in blue ("?").
#
new.hint = "?" + o.shortname + "||This point represents an entity, i.e. an object that appears and interacts in the game when you play the map. The exact kind of entity depends on its 'classname' (its name).\n\nThis handle lets you move the entity with the mouse. Normally, the mouvement is done by steps of the size of the grid : if the entity was not aligned on the grid before the movement, it will not be after it. Hold down Ctrl to force the entity to the grid."
#
# Return the handle
#
return h+[new]
else:
#
# No "origin".
#
return []
class FaceHandleCursor:
"Special class to compute the mouse cursor shape based on the visual direction of a face."
def getcursor(self, view):
n = view.proj(self.pos + self.face.normal) - view.proj(self.pos)
dx, dy = abs(n.x), abs(n.y)
if dx*2<=dy:
if (dx==0) and (dy==0):
return CR_ARROW
else:
return CR_SIZENS
elif dy*2<=dx:
return CR_SIZEWE
elif (n.x>0)^(n.y>0):
return CR_SIZENESW
else:
return CR_SIZENWSE
def completeredimage(face, new):
#
# Complete a red image with the whole polyhedron.
# (red images cannot be reduced to a single face; even if
# we drag just a face, we want to see the whole polyhedron)
#
gr = []
for src in face.faceof:
if src.type == ":p":
poly = quarkx.newobj("redimage:p")
t = src
while t is not None:
for q in t.subitems:
if (q.type==":f") and not (q is face):
poly.appenditem(q.copy())
t = t.treeparent
poly.appenditem(new.copy())
gr.append(poly)
if len(gr):
return gr
else:
return [new]
class FaceHandle(qhandles.GenericHandle):
"Center of a face."
undomsg = Strings[516]
hint = "move this face (Ctrl key: force center to grid)||This handle lets you scroll this face, thus distort the polyhedron(s) that contain it.\n\nNormally, the face can be moved by steps of the size of the grid; holding down the Ctrl key will force the face center to be exactly on the grid."
delta = self.face.normal * (self.face.normal*delta) # projection of 'delta' on the 'normal' line
new.translate(delta)
if flags&MB_DRAGGING: # the red image contains the whole polyhedron(s), not the single face
new = completeredimage(self.face, new)
else:
new = [new]
else:
new = None
return [self.face], new
def leave(self, editor):
src = self.face.faceof
if (len(src)==1) and (src[0].type == ":p"):
editor.layout.explorer.uniquesel = src[0]
class PFaceHandle(FaceHandle):
"Center of a face, but unselected (as part of a selected poly)."
def draw(self, view, cv, draghandle=None):
p = view.proj(self.pos)
if p.visible:
cv.reset()
cv.brushcolor = view.darkcolor
cv.rectangle(p.x-3, p.y-3, p.x+4, p.y+4)
def click(self, editor):
editor.layout.explorer.uniquesel = self.face
return "S"
def leave(self, editor):
pass
class MapRotateHandle(qhandles.Rotate3DHandle):
"Like Rotate3DHandle, but specifically for the map editor."
MODE = SS_MAP
class FaceNormalHandle(MapRotateHandle):
"3D rotating handle, for faces."
undomsg = Strings[517]
hint = "rotate this face (Ctrl key: force to a common angle)||This handle lets you rotate the face around its center. Use it to distort the polyhedron(s).\n\nYou can set any angle unless you hold down the Ctrl key; in this case, you can only set 'round' angle values. See the Configuration dialog box, Map, Display."
def __init__(self, center, vtx, face, scale1):
MapRotateHandle.__init__(self, center, face.normal, scale1, qhandles.mapicons[11])
if flags&MB_DRAGGING: # the red image contains the whole polyhedron(s), not the single face
new = completeredimage(self.face, new)
else:
new = [new]
return [self.face], new, av
class Angles3DHandle(MapRotateHandle):
"3D rotating handle, for 'angles'-like Specifics."
hint = "entity pointing angle (any 3D direction)||Lets you set the direction the entity is 'looking' at. Hold down Ctrl to force the angle to some 'round' value."
hint = "entity pointing angle (2D direction only, or up or down)||Lets you set the direction the entity is 'looking' at. This has various meaning for various entities : for most ones, it is the direction it is facing when the map starts; for buttons or doors, it is the direction the button or door moves.\n\nYou can set any horizontal angle, as well as 'up' and 'down'. Hold down Ctrl to force the angle to a 'round' value."
map = (qhandles.angle2vec, qhandles.vec2angle)
ii = 13
class PolyHandle(CenterHandle):
"Center of polyhedron Handle."
undomsg = Strings[515]
hint = "move polyhedron (Ctrl key: force center to grid)||Lets you move this polyhedron.\n\nYou can move it by steps equal to the grid size. This means that if it is not on the grid now, it will not be after the move, either. You can force it on the grid by holding down the Ctrl key, but be aware that this forces its center to the grid, not all its faces. For cubic polyhedron, you may need to divide the grid size by two before you get the expected results."
hint = "move vertex and distort polyhedron (Alt key: restricted to one face only)||By dragging this point, you can distort the polyhedron in a way that looks like you are moving the vertex of the polyhedron.\n\nBe aware that you might not always get the expected results, because you are not really dragging the vertex, but just rotating the adjacent faces in a way that simulates the vertex movement. If you move the vertex too far away, it might just disappear. Polyhedrons are always convex, so that you cannot do just anything you like with them.\n\nHolding down the Alt key to let only one face move. Holding down Ctrl will force the vertex to the grid."
# Compute the mean normal vector from the adjacent faces' normal vector.
#
n = reduce(lambda x,y: x+y, map(lambda f: f.normal, faces))
#
# Force "n" to be perpendicular to the screen direction.
#
vertical = view.vector(self.pos).normalized # vertical vector at this point
n = (n - vertical * (n*vertical)).normalized
#
# Find a "model" face for the new one.
#
bestface = faces[0]
for f in faces[1:]:
if abs(f.normal*vertical) < abs(bestface.normal*vertical):
bestface = f
#
# Build the new face.
#
newface = bestface.copy()
newface.shortname = "corner"
newface.distortion(n, self.pos)
#
# Move the face to its correct position.
#
delta = 0.5*(pt-self.pos)
delta = n * (delta*n)
newface.translate(delta)
#
# Insert the new face into the polyhedron.
#
undo = quarkx.action()
undo.put(self.poly, newface)
editor.ok(undo, Strings[563])
return [qmenu.item("&Cut out corner", cutcorner1click, "|This command cuts out the corner of the polyhedron. It does so by adding a new face near the vertex you right-clicked on. The new face is always perpendicular to the view."),
qmenu.sep,
qmenu.item("&Force to grid", forcegrid1click,
"force vertex to grid")] + self.OriginItems(editor, view)
self.hint = ("offset texture on face", "enlarge or distort 1st texture axis",
"enlarge or distort 2nd texture axis", "rotate texture")[n] + \
"||Use the 4 handles at the corners of this 'L' to scroll or rotate the texture on the face.\n\nThe center of the 'L' lets you scroll the texture; the two ends lets you enlarge and distort the texture in the corresponding directions; the 4th point lets you rotate the texture."
class RectSelDragObject(qhandles.RectangleDragObject):
"A red rectangle that selects the polyhedrons it touches."
Hint = hintPlusInfobaselink("Rectangular selection of POLYHEDRONS||Rectangular selection of POLYHEDRONS:\n\nAfter you click on this button, click and move the mouse on the map to draw a rectangle; all polyhedrons touching this rectangle will be selected.\n\nHold down Ctrl to prevent already selected polyhedron from being unselected first.", "intro.mapeditor.toolpalettes.mousemodes.html#selectpoly")
def rectanglesel(self, editor, x,y, rectangle):
if not ("T" in self.todo):
editor.layout.explorer.uniquesel = None
polylist = FindSelectable(editor.Root, ":p")
lastsel = None
for p in polylist:
if rectangle.intersects(p):
p.selected = 1
lastsel = p
if lastsel is not None:
editor.layout.explorer.focus = lastsel
editor.layout.explorer.selchanged()
#
# Mouse Clicking and Dragging on map views.
#
def MouseDragging(self, view, x, y, s, handle):
"Mouse Drag on a Map View."
#
# qhandles.MouseDragging builds the DragObject.
#
if handle is not None:
s = handle.click(self)
if s and ("S" in s):
self.layout.actionmpp() # update the multi-pages-panel
return qhandles.MouseDragging(self, view, x, y, s, handle, MapColor("GrayImage"))